package com.glut.campusrepair.config;

import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.net.ssl.*;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

@Configuration // 表明这是一个配置类，Spring 容器会在启动时处理该类
public class OkHttpConfiguration {

    // 从yml配置文件中读取配置值，并将其注入到相应的字段中
    @Value("${ok.http.connect-timeout}")
    private Integer connectTimeout;

    @Value("${ok.http.read-timeout}")
    private Integer readTimeout;

    @Value("${ok.http.write-timeout}")
    private Integer writeTimeout;

    @Value("${ok.http.max-idle-connections}")
    private Integer maxIdleConnections;

    @Value("${ok.http.keep-alive-duration}")
    private Long keepAliveDuration;

    @Bean // 定义一个 OkHttpClient 类型的 Bean，Spring 会将其管理并注入到需要的地方
    public OkHttpClient okHttpClient() {
        return new OkHttpClient.Builder()
                // 设置 SSL 套接字工厂，进行 SSL 证书的信任管理
                .sslSocketFactory(sslSocketFactory(), x509TrustManager())
                // 禁用连接失败时的重试
                .retryOnConnectionFailure(false)
                // 设置连接池
                .connectionPool(pool())
                // 设置连接超时时间
                .connectTimeout(connectTimeout, TimeUnit.SECONDS)
                // 设置读取超时时间
                .readTimeout(readTimeout, TimeUnit.SECONDS)
                // 设置写入超时时间
                .writeTimeout(writeTimeout, TimeUnit.SECONDS)
                // 忽略主机名验证
                .hostnameVerifier((hostname, session) -> true)
                // 可选：设置代理
//                 .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8080)))
                // 可选：添加拦截器
                // .addInterceptor()
                .build();
    }

    /*定义一个 X509TrustManager 类型的 BeanX509TrustManager 是 Java 中 TrustManager
     接口的一种具体实现，用于管理基于 X.509 证书的信任决策。它主要负责验证和管理客户端和服务器端的证书  */
    @Bean
    public X509TrustManager x509TrustManager() {//信任书
        return new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType)//在 SSL/TLS 连接建立过程中验证客户端证书的有效性和可信度
                    throws CertificateException {
                // 忽略客户端证书验证
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType)
                    throws CertificateException {
                // 忽略服务器证书验证
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                //这个方法的返回值告诉 SSL/TLS 引擎哪些证书是受信任的
                return new X509Certificate[0]; // 返回一个空的 X509Certificate 数组
            }
        };
    }

    @Bean // 定义一个 SSLSocketFactory 类型的 Bean
    public SSLSocketFactory sslSocketFactory() {
        try {
            // 创建一个 SSLContext 并初始化以信任所有证书            TLS 表示你正在使用 TLS 协议（传输层安全性协议），它是 SSL 的后继版本
            SSLContext sslContext = SSLContext.getInstance("TLS");// 获取一个 TLS 类型的 SSLContext 实例
            //TrustManager用于验证从对方（客户端或服务器）提供的证书链是否被信任  SecureRandom 实例，用于生成安全的随机数z
            sslContext.init(null, new TrustManager[]{x509TrustManager()}, new SecureRandom());
            //返回一个工厂实例，用于创建支持 SSL/TLS 的套接字（SSLSocket）。这个工厂实例可以用来在客户端和服务器之间建立安全的连接
            return sslContext.getSocketFactory();
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace(); // 捕获异常并打印堆栈跟踪
        }
        return null; // 如果出现异常，则返回 null
    }

    @Bean // 定义一个 ConnectionPool 类型的 Bean
    public ConnectionPool pool() {
        // 创建一个连接池，设置最大空闲连接数和保持时间
        return new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.SECONDS);
    }
}
